with Ada.Finalization;
with SDL.Events, SDL.Keysym;
with Ada.Exceptions;
with Legend.Renders;
package Legend.Interactives is
   use Ada.Finalization;

   -- 显示流程:
   -- 每个场景或精灵继承自Interactive_Type, 并重载Paint方法实现绘制过程
   -- 在初始化设置帧频(创建一个渲染定时器)
   -- Interactive_Type调用Run进入主循环
   -- 主循环中侦听交互消息及时钟消息
   -- 当收到渲染时钟消息时调用Repaint进行重绘(重绘时会检查画布是否已改变)
   -- 当收到其他时钟消息不能处理的冒泡到来源场景
   -- 当收到其他消息时调用相应的重载后的On_XXXX处理消息(如On_Key_Up)
   -- 消息处理过程中可以调用Canvas.Invalidate指示画布已改变

   -- TODO
   -- implents Move_XXX methods

   type Interactive_Type is new Limited_Controlled and Renders.Painter_Type with 
   record
      Parent    : access Interactive_Type'Class := null;
      Canvas    : Renders.Canvas_Type(Interactive_Type'Unrestricted_Access); 
      Timer     : Hash_Type;
      Active    : Boolean;
      Disabled  : Boolean := False;
   end record;

   -- 消息处理函数
   -- 重载此函数实现具体的逻辑
   procedure Dispatch (
      this : in out Interactive_Type;
      Message : SDL.Events.Event_t;
      Cancel_Bubble : in out Boolean
      );

   procedure On_Key_Down (
      this : in out Interactive_Type;
      Message : SDL.Events.Keyboard_Event_t;
      Cancel_Bubble : in out Boolean
      ) is null;

   procedure On_Key_Up (
      this : in out Interactive_Type;
      Message : SDL.Events.Keyboard_Event_t;
      Cancel_Bubble : in out Boolean) is null;

   procedure On_Mouse_Move (
      this : in out Interactive_Type;
      Message : SDL.Events.Mouse_Motion_Event_t;
      Cancel_Bubble : in out Boolean) is null;

   procedure On_Mouse_Down (
      this : in out Interactive_Type;
      Message : SDL.Events.Mouse_Button_Event_t;
      Cancel_bubble : in out Boolean) is null;

   procedure On_Mouse_Up (
      this : in out Interactive_Type;
      Message : SDL.Events.Mouse_Button_Event_t;
      Cancel_bubble : in out Boolean
      ) is null;

   procedure On_Timer (
      this          : in out Interactive_Type;
      Timer         : Hash_Type;
      Count         : Natural;
      Cancel_Bubble : in out Boolean
      );

   procedure On_User_Event (
      this : in out Interactive_Type;
      message : SDL.Events.User_Event_t;
      cancel_bubble : in out Boolean
      ) is null;

   -- implements Renders.Painter_Type
   procedure Paint (this : in out Interactive_Type) is null;

   procedure On_Before_Run (this : in out Interactive_Type) is null;

   -- before run
   -- you should setup the canvas surface
   procedure Run (this : in out Interactive_Type);

   procedure Switch_To_Movie_Mode (
      this : in out Interactive_Type;
      Over : not null access function return Boolean
      );

   procedure Close (this : in out Interactive_Type);

   function Expect_Char (
      this : in out Interactive_Type;
      Chars : String;
      Default : Character
      ) return Character;

   function Expect_Input (
      this : in out Interactive_Type;
      text : String
      ) return Boolean;

   function Expect_Number (
      this : in out Interactive_Type
      ) return String;

   -- SDL.Events.Filter_t
   function Disable_Input_Filter (
      Message   : SDL.Events.Event_Access_t
      ) return Interfaces.C.int;
   pragma Convention (C, Disable_Input_Filter);

   procedure Trap_Timer (
      Message : SDL.Events.Event_t;
      Process : access procedure (Timer : Hash_Type; Count : Natural) := null
      );

   type Key_Array_Type is array(Positive range <>) of SDL.Keysym.Key_t;

   -- if timeout return k_unknown
   function Wait_Key_Or_Timeout (
      Timeout : Duration;
      Keys    : Key_Array_Type := (1 .. 0 => <>)
      ) return SDL.Keysym.Key_t;

   procedure Wait_Any_Key;

   procedure Start_Play_Movie (
      Movie   : in out Movie_Type;
      Expired : Duration := Loop_Infinite
      );

   procedure Stop_Play_Movie (Movie : in out Movie_Type);

private


end Legend.Interactives;
